﻿using System.Collections.Generic;
using System.Linq;
using Agr.CQRS.Domain.Events;
using Agr.CQRS.Util;
using log4net;

namespace Agr.CQRS.Domain
{
    public class Aggregate
    {
        private static ILog Logger = LogManager.GetLogger(typeof(Aggregate));

        internal IList<Entity> Entities = new List<Entity>();
        internal IList<DomainEvent> UnCommittedEvents = new List<DomainEvent>();

        public void RegisterEntity(Entity e)
        {
            e.EntityNumber = Entities.Count;
            Entities.Add(e);
            e.Aggregate = this;
        }

        internal AggregateRoot AggregateRoot
        {
            get
            {
                return (AggregateRoot)Entities[0];
            }
        }

        public void Handle(DomainEvent ev)
        {
            var entity = (from e in Entities where e.EntityNumber == ev.Entitynumber select e).First();
            invokeHandlerFor(ev, entity);
            AggregateRoot.Version += 1;

            if (!ev.Replaying)
            {
                UnCommittedEvents.Add(ev);
                Logger.InfoFormat("{0}.{1} now has version {2}", AggregateRoot.GetType().Name, AggregateRoot.Id, AggregateRoot.Version);
            }
        }
        
        private void invokeHandlerFor(DomainEvent ev, Entity entity)
        {
            var handlerMethod = Reflection.FindMethodWithOneParameterOfType(entity.GetType(), ev.GetType());
            if (handlerMethod == null)
                throw new UnrecognizedDomainEventException(ev);

            handlerMethod.Invoke(entity, new object[] { ev });
        }

    }
}
